package com.sangeng;

import com.alibaba.fastjson.JSON;
import com.sangeng.annocation.SystemLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

@Component
@Slf4j
//标注为切面类
@Aspect

public class SysLog {
    //定义切点,指定切入点为注解标注的地方
@Pointcut("@annotation(com.sangeng.annocation.SystemLog)")
    public void pt(){

    }
    //通知方法,需要传入切点
    @Around("pt()")
  public Object printLog(ProceedingJoinPoint joinPoint) throws Throwable {
    
    Object ret;
  try{  //目标方法执行之前做的事
      handleBefore(joinPoint);
    //目标方法执行
    ret =joinPoint.proceed();
    
    //目标方法执行之后
      handleAfter(ret);
    } finally {
      //系统换行符
      log.info("=============End============="+ System.lineSeparator());
  }
  
  //必须return回去，否者目标方法加强后就没有返回值了
  return ret;
  }
    private void handleBefore(ProceedingJoinPoint joinPoint) {
    //获取但前线程的requestAttributes对象，进而获取request
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        //获取被增强方法上的注解对象,进而就可以获取到切点上的方法
        SystemLog systemLog= getSystemLog(joinPoint);

        log.info("=======Start=======");
        // 打印请求 URL
        log.info("URL            : {}",request.getRequestURL());
        // 打印描述信息
        log.info("BusinessName   : {}", systemLog.businessName());
        // 打印 Http method
        log.info("HTTP Method    : {}", request.getMethod());
        // 打印调用 controller 的全路径以及执行方法
        log.info("Class Method   : {}.{}", joinPoint.getSignature().getDeclaringType(),((MethodSignature)(joinPoint.getSignature())).getName());
        // 打印请求的 IP
        log.info("IP             : {}",request.getRemoteHost());
        // 打印请求入参
        log.info("Request Args   : {}", JSON.toJSONString(joinPoint.getArgs()));

    }


    private void handleAfter(Object ret) {
        // 打印出参
        log.info("Response       : {}",JSON.toJSONString(ret));
        // 结束后换行
        log.info("=======End=======" + System.lineSeparator());
    }
    private SystemLog getSystemLog(ProceedingJoinPoint joinPoint) {
    //获取方法签名，相当于把方法和方法上的注解封装成一个对象，可以通过该对象获取方法以及注解等
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        //获取方法上的指定类型的注解
        SystemLog annotation = signature.getMethod().getAnnotation(SystemLog.class);
        return annotation;
    }


}
